
#include <cTools/cTools.h>
#include <unistd.h>
#include <string.h>

typedef struct _C_Event1
{
	C_Event	Event;
	char*	Msg;
} C_Event1;

typedef C_Event1* C_Event1_Ptr;

C_Event1_Ptr
C_Event1_New(const char *msg);

void
C_Event1_Init(C_Event1_Ptr, const char *);

void
C_Event1_Cleanup(C_Event1_Ptr);


typedef struct _C_Event2
{
	C_Event1	Event;
	char*	Msg;
} C_Event2;

typedef C_Event2* C_Event2_Ptr;

C_Event2_Ptr
C_Event2_New(const char*, const char*);

void
C_Event2_Init(C_Event2_Ptr, const char*, const char*);

void
C_Event2_Cleanup(C_Event2_Ptr);


int
C_Event1_Handler(C_Event_Ptr);

int
C_Event2_Handler(C_Event_Ptr);

/******************************************************************************/

C_Event1_Ptr
C_Event1_New(const char *msg)
{
	C_Event1_Ptr p = C_Malloc(sizeof(C_Event1));
	C_Event1_Init(p, msg);
	return p;
}

void
C_Event1_Init(C_Event1_Ptr p, const char *msg)
{
	// intialize base structure
	C_Event_Init((C_Event_Ptr)p, C_Event1_Handler);
	C_EVENT_SET_CLEANUP(p, C_Event1_Cleanup);
	p->Msg = strdup(msg);
}

void
C_Event1_Cleanup(C_Event1_Ptr p)
{
	free(p->Msg);
	C_Event_Base_Cleanup((C_Event_Ptr)p);
}


C_Event2_Ptr
C_Event2_New(const char *msg1, const char *msg2)
{
	C_Event2_Ptr p = C_Malloc(sizeof(C_Event2));
	C_Event2_Init(p, msg1, msg2);
	return p;
}

void
C_Event2_Init(C_Event2_Ptr p, const char *msg1, const char *msg2)
{
	// intialize base structure
	C_Event1_Init((C_Event1_Ptr)p, msg1);
	C_EVENT_SET_HANDLER(p, C_Event2_Handler);
	C_EVENT_SET_CLEANUP(p, C_Event2_Cleanup);
	p->Msg = strdup(msg2);
}

void
C_Event2_Cleanup(C_Event2_Ptr p)
{
	free(p->Msg);
	C_Event1_Cleanup((C_Event1_Ptr)p);
}


typedef struct _C_Dummy_Event
{
	C_Event	Event;
	int		IntParam;
	char	ByteArray[32];
} C_Dummy_Event;

typedef C_Dummy_Event* C_Dummy_Event_Ptr;

C_Dummy_Event_Ptr
C_Dummy_Event_New(void);

int
C_Dummy_Event_Handler(C_Dummy_Event_Ptr p);

/******************************************************************************/

C_Dummy_Event_Ptr
C_Dummy_Event_New(void)
{
	C_Dummy_Event_Ptr p = C_Malloc(sizeof(C_Dummy_Event));
	C_Event_Init((C_Event_Ptr)p, (C_Event_Handler_t)C_Dummy_Event_Handler);
	return p;
}

/******************************************************************************/

int
C_Dummy_Event_Handler(C_Dummy_Event_Ptr p)
{
	printf("Processing dummy event!\r\n");
	return 1;
}

int
C_Event1_Handler(C_Event_Ptr _p)
{
	C_Event1_Ptr p = (C_Event1_Ptr)_p;
	printf("msg = %s\r\n", p->Msg);
	return 1;
}

int
C_Event2_Handler(C_Event_Ptr _p)
{
	C_Event2_Ptr p = (C_Event2_Ptr)_p;
	printf("msg = %s\r\n", p->Msg);
	return 1;
}

void
C_Dummy_Timer_Handler(C_Timer_Ptr t)
{
	printf("Processing dummy timer (id = %d)!\r\n", t->UserId);
}

C_Event_Thread 	EvThread;
C_Event_Thread 	EvThread2;
C_Timer_Manager	TmrThread;
C_Timer			Tmr;
C_Queue			Queue;


int main(int argc, char *argv[])
{
	char buf[64];

	C_Queue_Init(&Queue, NULL);

	C_Event_Thread_Init(&EvThread, &Queue);
	C_Event_Thread_Init(&EvThread2, &Queue);

	C_Timer_Manager_Init(&TmrThread);

	C_Timer_Init(&Tmr, 1000, C_Dummy_Timer_Handler, C_True);

	C_Timer_Set_User_Data(&Tmr, NULL, 1);

	C_Timer_Manager_Start(&TmrThread, &Tmr);

	C_Thread_Run((C_Thread_Ptr)&EvThread, C_False, NULL);
	C_Thread_Run((C_Thread_Ptr)&EvThread2, C_True, NULL);

	C_Thread_Run((C_Thread_Ptr)&TmrThread, C_False, NULL);

	DBG("Starting main loop...");

	while (fgets(buf, sizeof(buf), stdin))
	{
		if (strstr(buf, "quit"))
			break;

		if (strstr(buf, "ev1"))
		{
			C_Event1_Ptr e1 = C_Event1_New("event-1");
			C_Queue_Put(EvThread.Queue, e1);
		}
		else if (strstr(buf, "ev2"))
		{
			C_Event2_Ptr e2 = C_Event2_New("event-1", "event-2");
			C_Queue_Put(EvThread.Queue, e2);
		}
		else
		{
			C_Dummy_Event_Ptr p = C_Dummy_Event_New();
			C_Queue_Put(EvThread.Queue, p);
		}


	}

	DBG("Terminating main loop...");


	C_Thread_Stop((C_Thread_Ptr)&EvThread);
	C_Thread_Stop((C_Thread_Ptr)&EvThread2);

	C_Thread_Stop((C_Thread_Ptr)&TmrThread);

	C_Thread_Cleanup((C_Thread_Ptr)&EvThread);
	C_Thread_Cleanup((C_Thread_Ptr)&TmrThread);

	return 0;
}
